#include "FluidSimulator.h"
#include <glut.h>
#include <math.h>

int    winWidth, winHeight;
int    lmx, lmy;

FluidSimulator* fluid;

#define floor(x) ((x)>=0.0?((int)(x)):(-((int)(1-(x)))))

void drawField(void) {
	int        i, j, idx, DIM;

	DIM = fluid->scale;

	double  wn = (double)winWidth / (double)(DIM + 1);   
	double  hn = (double)winHeight / (double)(DIM + 1);  
	double     px, py;


	for (j = 0; j < DIM - 1; j++) {
		glBegin(GL_TRIANGLE_STRIP);

		i = 0;
		px = wn + (double)i * wn;
		py = hn + (double)j * hn;
		idx = (j * DIM) + i;
		glColor3f(fluid->d[idx], fluid->d[idx], fluid->d[idx]);
		glVertex2f(px, py);

		for (i = 0; i < DIM - 1; i++) {
			px = wn + (double)i * wn;
			py = hn + (double)(j + 1) * hn;
			idx = ((j + 1) * DIM) + i;
			glColor3f(fluid->d[idx], fluid->d[idx], fluid->d[idx]);
			glVertex2f(px, py);

			px = wn + (double)(i + 1) * wn;
			py = hn + (double)j * hn;
			idx = (j * DIM) + (i + 1);
			glColor3f(fluid->d[idx], fluid->d[idx], fluid->d[idx]);
			glVertex2f(px, py);
		}

		px = wn + (double)(DIM - 1) * wn;
		py = hn + (double)(j + 1) * hn;
		idx = ((j + 1) * DIM) + (DIM - 1);
		glColor3f(fluid->d[idx], fluid->d[idx], fluid->d[idx]);
		glVertex2f(px, py);

		glEnd();
	}

}

void display(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	drawField();

	glFlush();
	glutSwapBuffers();
}

void reshape(int w, int h) {
	glViewport(0.0f, 0.0f, (GLfloat)w, (GLfloat)h);
	glMatrixMode(GL_PROJECTION);  
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
	winWidth = w;
	winHeight = h;
}

void drag(int mx, int my) {
	int     xi;
	int     yi;
	double  dx, dy, len;
	int     X, Y;
	int DIM;

	DIM = fluid->scale;


	xi = (int)floor((double)(DIM + 1) * ((double)mx / (double)winWidth));
	yi = (int)floor((double)(DIM + 1) * ((double)(winHeight - my) / (double)winHeight));

	X = xi;
	Y = yi;

	if (X > (DIM - 1)) {
		X = DIM - 1;
	}
	if (Y > (DIM - 1)) {
		Y = DIM - 1;
	}
	if (X < 0) {
		X = 0;
	}
	if (Y < 0) {
		Y = 0;
	}

	my = winHeight - my;
	dx = mx - lmx;
	dy = my - lmy;
	len = sqrt(dx * dx + dy * dy);
	if (len != 0.0) { 
		dx *= 0.1 / len;
		dy *= 0.1 / len;
	}
	fluid->f2u[Y * DIM + X] += dx;
	fluid->f2v[Y * DIM + X] += dy;

	fluid->d[Y * DIM + X] = 40.0f;

	lmx = mx;
	lmy = my;
}

void idle(void) {

	fluid->Update(0.4);

	glutPostRedisplay();
}

void main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize(500, 500);
	glutCreateWindow("Real-time wispy smoke");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutIdleFunc(idle);
	glutMotionFunc(drag);

	fluid = new FluidSimulator;

	fluid->InitSimulator(300,0.0001);

	glutMainLoop();
}